package com.example.demo.aop;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.base.AopException;
import com.example.demo.base.ReqParam;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;


@Aspect
@Component
public class CommonLoggerAspect {

    private static final Logger log = LoggerFactory.getLogger(CommonLoggerAspect.class);

    @Pointcut("execution (* com.example.demo.controller.*Controller.*(..))")
    public void controllerAspect() {
    }

    @SuppressWarnings("rawtypes")
    @Around("controllerAspect()")
    public Object controllerAround(ProceedingJoinPoint joinPoint) throws Throwable{
        /**
         * 接口增加日志
         */
        String classAndMethodName = null;
        //获取当前请求属性集
        ServletRequestAttributes  sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //获取请求
        HttpServletRequest request = sra.getRequest();
        //获取请求地址
        String requestUrl = request.getRequestURL().toString();
        //记录请求地址
        log.info("请求开始:路径[{}]", requestUrl);
        //记录请求开始时间
        long startTime = System.currentTimeMillis();
        try {
            Class<?> target = joinPoint.getTarget().getClass();
            Class<?>[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
            String methodName = joinPoint.getSignature().getName();
            //获取当前执行方法
            Method currentMethod = target.getMethod(methodName, par);
            //拼接输出字符串
            classAndMethodName = target.getName() + "的" + currentMethod.getName() + "方法";
            log.info("正在执行：{}", classAndMethodName);
            //获取切点参数
            List<Object> list = Arrays.asList(joinPoint.getArgs());
            if (list != null && list.size() > 0) {
                for(Object object : list){
                    if(object instanceof MultipartFile) {
                        log.info("入参:{}", ((MultipartFile) object).isEmpty() ? "空文件" : ((MultipartFile)object).getName());
                    } else if(object instanceof ReqParam){
                        log.info("入参:{}", ((ReqParam) object).getData().toString());
                    }else if(object == null) {
                        log.info("入参: ");
                    }else{
                        log.info("入参:{}", object.toString());
                    }
                }
            }
        } catch (Exception e) {
            log.error("记录日志的时出现异常，异常信息：{}", e);
            throw new AopException("记录日志的时出现异常");
        }
        Object object = joinPoint.proceed();
        if (object != null) {
            log.info("执行方法：{}，返回参数:{}", classAndMethodName, JSONObject.toJSONString(object));
        }else{
            log.info("执行方法：{}，无返回参数！", classAndMethodName);
        }
        long endTime = System.currentTimeMillis();
        log.info("请求结束:路径[{}]响应时间{}毫秒", requestUrl, endTime-startTime);
        return object;
    }
}
